function NavController()
{
	this.pageCompletionStates = new PageStates();
	this.pageLockedStates = new PageStates();
	this.pageHiddenStates = new PageStates();
	this.topicCompletionStates = new TopicStates();
	this.topicLockedStates = new TopicStates();
	this.topicHiddenStates = new TopicStates();
	this.compress = false;
	this.prereqs = new Prerequisites();
	
	this.isDirty = NavControllerIsDirty;
	
	// PageCompletionStates interface
	this.clearPageCompletionStates = NavControllerClearPageCompletionStates;
	this.loadPageCompletionStates = NavControllerLoadPageCompletionStates;
	this.dumpPageCompletionStates = NavControllerDumpPageCompletionStates;
	this.setPageCompletionState = NavControllerSetPageCompletionState;
	this.getPageCompletionState = NavControllerGetPageCompletionState;

	// PageLockedStates interface
	this.clearPageLockedStates = NavControllerClearPageLockedStates;
	this.loadPageLockedStates = NavControllerLoadPageLockedStates;
	this.dumpPageLockedStates = NavControllerDumpPageLockedStates;
	this.setPageLockedState = NavControllerSetPageLockedState;
	this.getPageLockedState = NavControllerGetPageLockedState;

	// PageHiddenStates interface
	this.clearPageHiddenStates = NavControllerClearPageHiddenStates;
	this.loadPageHiddenStates = NavControllerLoadPageHiddenStates;
	this.dumpPageHiddenStates = NavControllerDumpPageHiddenStates;
	this.setPageHiddenState = NavControllerSetPageHiddenState;
	this.getPageHiddenState = NavControllerGetPageHiddenState;

	// TopicCompletionStates interface
	this.clearTopicCompletionStates = NavControllerClearTopicCompletionStates;
	this.loadTopicCompletionStates = NavControllerLoadTopicCompletionStates;
	this.dumpTopicCompletionStates = NavControllerDumpTopicCompletionStates;
	this.setTopicCompletionState = NavControllerSetTopicCompletionState;
	this.getTopicCompletionState = NavControllerGetTopicCompletionState;

	// TopicLockedStates interface
	this.clearTopicLockedStates = NavControllerClearTopicLockedStates;
	this.loadTopicLockedStates = NavControllerLoadTopicLockedStates;
	this.dumpTopicLockedStates = NavControllerDumpTopicLockedStates;
	this.setTopicLockedState = NavControllerSetTopicLockedState;
	this.getTopicLockedState = NavControllerGetTopicLockedState;

	// TopicHiddenStates interface
	this.clearTopicHiddenStates = NavControllerClearTopicHiddenStates;
	this.loadTopicHiddenStates = NavControllerLoadTopicHiddenStates;
	this.dumpTopicHiddenStates = NavControllerDumpTopicHiddenStates;
	this.setTopicHiddenState = NavControllerSetTopicHiddenState;
	this.getTopicHiddenState = NavControllerGetTopicHiddenState;

	// Prerequisites interface
	this.clearPrerequisites = NavControllerClearPrerequisites;
	this.loadPrerequisites = NavControllerLoadPrerequisites;
	this.dumpPrerequisites = NavControllerDumpPrerequisites;
	this.setPrerequisites = NavControllerSetPrerequisites;
	this.getPrerequisites = NavControllerGetPrerequisites;
	this.metAllPrerequisites = NavControllerMetAllPrerequisites;
	this.removePrerequisites = NavControllerRemovePrerequisites;
	this.markPrerequisitesAsComplete = NavControllerMarkPrerequisitesAsComplete;
	this.markPrerequisitesAsIncomplete = NavControllerMarkPrerequisitesAsIncomplete;	
	this.getIncompletePrerequisites = NavControllerGetIncompletePrerequisites;
		
	// NavController interface
	this.dump = NavControllerDump;
	this.load = NavControllerLoad;
	this.clear = NavControllerClear;
	this.setCompression = NavControllerSetCompression;
	this.checkForTopicCompletion = NavControllerCheckForTopicCompletion;
}

function NavControllerSetCompression(flag)
{
	this.compress = flag;
	this.pageCompletionStates.compress = flag;
	this.pageLockedStates.compress = flag;
	this.pageHiddenStates.compress = flag;
	this.topicCompletionStates.compress = flag;
	this.topicLockedStates.compress = flag;
	this.topicHiddenStates.compress = flag;
	this.prereqs.compress = flag;
}

function NavControllerLoadPrerequisites(dataString)
{
	this.prereqs.load(dataString);
}

function NavControllerDumpPrerequisites()
{
	return this.prereqs.dump();
}

function NavControllerClearPrerequisites()
{
	this.prereqs.clear();
}

function NavControllerSetPrerequisites(obj1)
{
	for (var i=1;i<NavControllerSetPrerequisites.arguments.length;i++)
	{
		this.prereqs.addPrerequisites(obj1, NavControllerSetPrerequisites.arguments[i])
	}
}

function NavControllerGetPrerequisites(obj)
{
	return this.prereqs.getPrerequisites(obj);
}

function NavControllerGetIncompletePrerequisites(obj)
{
	var prereqArray = this.getPrerequisites(obj);
	var incompleteArray = new Array();
	for (var i=0;i<prereqArray.length;i++)
	{
		if (prereqArray[i].type == "Page")
		{
			if (!this.getPageCompletionState(prereqArray[i]))
			{
				incompleteArray[incompleteArray.length] = prereqArray[i];
			}
		}
		else
		{
			if (!this.getTopicCompletionState(prereqArray[i]))
			{
				incompleteArray[incompleteArray.length] = prereqArray[i];
			}
		}
	}
	return incompleteArray;
}

function NavControllerRemovePrerequisites(obj)
{
	if (NavControllerRemovePrerequisites.arguments.length < 2)
	{
		var prereqArray = this.getPrerequisites(obj);
		for (var i=0;i<prereqArray.length;i++)
		{
			this.prereqs.removePrerequisites(obj, prereqArray[i]);
		}
	}
	else
	{
		for (var i=1;i<NavControllerRemovePrerequisites.arguments.length;i++)
		{
			this.prereqs.removePrerequisites(obj, NavControllerRemovePrerequisites.arguments[i]);
		}
	}
}

function NavControllerLoad(dataString)
{
	this.clear();
	if (dataString == "" || dataString == null)
	{
		dataString = "XXXXXX";
	}
	
	var index = dataString.indexOf("X");
	this.loadPageCompletionStates(dataString.slice(0,index));
	dataString = dataString.slice(index+1,dataString.length);

	index = dataString.indexOf("X");
	this.loadPageLockedStates(dataString.slice(0,index));
	dataString = dataString.slice(index+1,dataString.length);
	
	index = dataString.indexOf("X");
	this.loadPageHiddenStates(dataString.slice(0,index));
	dataString = dataString.slice(index+1,dataString.length);
	
	index = dataString.indexOf("X");
	this.loadTopicCompletionStates(dataString.slice(0,index));
	dataString = dataString.slice(index+1,dataString.length);
	
	index = dataString.indexOf("X");
	this.loadTopicLockedStates(dataString.slice(0,index));
	dataString = dataString.slice(index+1,dataString.length);
	
	index = dataString.indexOf("X");
	this.loadTopicHiddenStates(dataString.slice(0,index));
	dataString = dataString.slice(index+1,dataString.length);
	
	this.loadPrerequisites(dataString);
}

function NavControllerDump()
{
	return (this.dumpPageCompletionStates() + "X" + this.dumpPageLockedStates() + "X" + this.dumpPageHiddenStates() + "X" + this.dumpTopicCompletionStates() + "X" + this.dumpTopicLockedStates() + "X" + this.dumpTopicHiddenStates() + "X" + this.dumpPrerequisites());
}

function NavControllerClear()
{
	this.clearPageCompletionStates();
	this.clearPageLockedStates();
	this.clearPageHiddenStates();
	this.clearTopicCompletionStates();
	this.clearTopicLockedStates();
	this.clearTopicHiddenStates();
	this.clearPrerequisites();
}

function NavControllerMetAllPrerequisites(obj)
{
	var prereqArray = this.getPrerequisites(obj);
	for (var i=0;i<prereqArray.length;i++)
	{
		if (prereqArray[i].type == "Page")
		{
			if (!this.getPageCompletionState(prereqArray[i]))
			{
				return false;
			}
		}
		else if (prereqArray[i].type == "Topic")
		{
			if (!this.getTopicCompletionState(prereqArray[i]))
			{
				return false;
			}
		}
	}
	return true;
}

function NavControllerMarkPrerequisitesAsComplete(obj)
{
	var prereqArray = this.getPrerequisites(obj);
	for (var i=0;i<prereqArray.length;i++)
	{
		if (prereqArray[i].type == "Page")
		{
			this.setPageCompletionState(prereqArray[i], true);
		}
		else if (prereqArray[i].type == "Topic")
		{
			this.setTopicCompletionState(prereqArray[i], true);
		}
	}
}

function NavControllerMarkPrerequisitesAsIncomplete(obj)
{
	var prereqArray = this.getPrerequisites(obj);
	for (var i=0;i<prereqArray.length;i++)
	{
		if (prereqArray[i].type == "Page")
		{
			this.setPageCompletionState(prereqArray[i], false);
		}
		else if (prereqArray[i].type == "Topic")
		{
			this.setTopicCompletionState(prereqArray[i], false);
		}
	}
}

// Takes a Topic object and returns true if all of the pages
// in the specified topic have been completed.  If a subtopic
// is passed, only the subtopic pages are evaluated.  If a topic
// is passed, the topic pages and all the subtopic pages
// will be evaluated.
function NavControllerCheckForTopicCompletion(objTopic)
{
	if (objTopic.subtopic == 0) // Entire Topic
	{
		for (var i=0;i<pageTitles[objTopic.section-1][objTopic.topic-1].length;i++)
		{
			if (!this.getPageCompletionState(new Page(objTopic.section, objTopic.topic, 0, (i+1))))
			{
				return false;
			}
		}
		if (subtopicPageTitles != null && subtopicPageTitles[objTopic.section-1] != null && subtopicPageTitles[objTopic.section-1][objTopic.topic-1] != null)
		{
			for (var i=0;i<subtopicPageTitles[objTopic.section-1][objTopic.topic-1].length;i++)
			{
				if (!this.checkForTopicCompletion(new Topic(objTopic.section,objTopic.topic,(i+1))))
				{
					return false;
				}
			}
		}
	}
	else // Subtopic
	{
		for (var t=0;t<subtopicPageTitles[objTopic.section-1][objTopic.topic-1][objTopic.subtopic-1].length;t++)
		{
			if (!this.getPageCompletionState(new Page(objTopic.section, objTopic.topic, objTopic.subtopic, (t+1))))
			{
				return false;
			}
		}
	}

	return true;
}

function NavControllerIsDirty()
{
	return (this.pageCompletionStates.isDirty() || this.pageLockedStates.isDirty() || this.pageHiddenStates.isDirty() || this.topicCompletionStates.isDirty() || this.topicLockedStates.isDirty() || this.topicHiddenStates.isDirty() || this.prereqs.isDirty());
}

//////////////////////////////////////////////////
//       PageCompletionStates interface         //
//////////////////////////////////////////////////
function NavControllerClearPageCompletionStates()
{
	this.pageCompletionStates.clear();
}
function NavControllerLoadPageCompletionStates(dataString)
{
	this.pageCompletionStates.load(dataString);
}
function NavControllerDumpPageCompletionStates()
{
	return this.pageCompletionStates.dump();
}
function NavControllerSetPageCompletionState(obj, flag)
{
	if (flag)
	{
		this.pageCompletionStates.setPage(obj);
	}
	else
	{
		this.pageCompletionStates.resetPage(obj);
	}
}
function NavControllerGetPageCompletionState(obj)
{
	return this.pageCompletionStates.getPageState(obj);
}
//////////////////////////////////////////////////
//         PageLockedStates interface           //
//////////////////////////////////////////////////
function NavControllerClearPageLockedStates()
{
	this.pageLockedStates.clear();
}
function NavControllerLoadPageLockedStates(dataString)
{
	this.pageLockedStates.load(dataString);
}
function NavControllerDumpPageLockedStates()
{
	return this.pageLockedStates.dump();
}
function NavControllerSetPageLockedState(obj, flag)
{
	if (flag)
	{
		this.pageLockedStates.setPage(obj);
	}
	else
	{
		this.pageLockedStates.resetPage(obj);
	}
}
function NavControllerGetPageLockedState(obj)
{
	return this.pageLockedStates.getPageState(obj);
}
//////////////////////////////////////////////////
//         PageHiddenStates interface           //
//////////////////////////////////////////////////
function NavControllerClearPageHiddenStates()
{
	this.pageHiddenStates.clear();
}
function NavControllerLoadPageHiddenStates(dataString)
{
	this.pageHiddenStates.load(dataString);
}
function NavControllerDumpPageHiddenStates()
{
	return this.pageHiddenStates.dump();
}
function NavControllerSetPageHiddenState(obj, flag)
{
	if (flag)
	{
		this.pageHiddenStates.setPage(obj);
	}
	else
	{
		this.pageHiddenStates.resetPage(obj);
	}
}
function NavControllerGetPageHiddenState(obj)
{
	return this.pageHiddenStates.getPageState(obj);
}
//////////////////////////////////////////////////
//       TopicCompletionStates interface        //
//////////////////////////////////////////////////
function NavControllerClearTopicCompletionStates()
{
	this.topicCompletionStates.clear();
}
function NavControllerLoadTopicCompletionStates(dataString)
{
	this.topicCompletionStates.load(dataString);
}
function NavControllerDumpTopicCompletionStates()
{
	return this.topicCompletionStates.dump();
}
function NavControllerSetTopicCompletionState(obj, flag)
{
	if (flag)
	{
		this.topicCompletionStates.setTopic(obj);
	}
	else
	{
		this.topicCompletionStates.resetTopic(obj);
	}
}
function NavControllerGetTopicCompletionState(obj)
{
	return this.topicCompletionStates.getTopicState(obj);
}
//////////////////////////////////////////////////
//         TopicLockedStates interface          //
//////////////////////////////////////////////////
function NavControllerClearTopicLockedStates()
{
	this.topicLockedStates.clear();
}
function NavControllerLoadTopicLockedStates(dataString)
{
	this.topicLockedStates.load(dataString);
}
function NavControllerDumpTopicLockedStates()
{
	return this.topicLockedStates.dump();
}
function NavControllerSetTopicLockedState(obj, flag)
{
	if (flag)
	{
		this.topicLockedStates.setTopic(obj);
	}
	else
	{
		this.topicLockedStates.resetTopic(obj);
	}
}
function NavControllerGetTopicLockedState(obj)
{
	return this.topicLockedStates.getTopicState(obj);
}
//////////////////////////////////////////////////
//         TopicHiddenStates interface          //
//////////////////////////////////////////////////
function NavControllerClearTopicHiddenStates()
{
	this.topicHiddenStates.clear();
}
function NavControllerLoadTopicHiddenStates(dataString)
{
	this.topicHiddenStates.load(dataString);
}
function NavControllerDumpTopicHiddenStates()
{
	return this.topicHiddenStates.dump();
}
function NavControllerSetTopicHiddenState(obj, flag)
{
	if (flag)
	{
		//alert("Hiding topic " + obj.section + "t" + obj.topic + "s" + obj.subtopic);
		this.topicHiddenStates.setTopic(obj);
	}
	else
	{
		this.topicHiddenStates.resetTopic(obj);
	}
}
function NavControllerGetTopicHiddenState(obj)
{
	return this.topicHiddenStates.getTopicState(obj);
}

